﻿using StableDiffusionTools.Oobabooga;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LLMEvaluation.Framework
{
    public class ModelEntry : INotifyPropertyChanged
    {
        public string Name { get; set; } = "";
        public List<Message> ResponseMessages { get; set; } = new List<Message>();

        private string response = "";
        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public string Response
        {
            get => response;
            set
            {
                response = value;
                NotifyPropertyChanged();
            }
        }

        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public string ResponseFormatted { get; set; } = "";

        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public bool HasSingleResponseMessage { get => ResponseMessages != null && ResponseMessages.Count == 1; }

        private bool isMarked = false;
        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public bool IsMarked
        {
            get => isMarked;
            set
            {
                isMarked = value;
                NotifyPropertyChanged();
            }
        }

        private InferenceState inference = InferenceState.Idle;
        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public InferenceState Inference
        {
            get => inference;
            set
            {
                inference = value;
                NotifyPropertyChanged();
            }
        }

        [JsonIgnore(Condition = JsonIgnoreCondition.Always)]
        public List<string> Marks { get; set; } = new List<string>();

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        public ModelEntry()
        {
            Update();
        }

        public void ClearResponseMessages()
        {
            ClearMarked();
            SetResponseMessages(new List<Message>());
        }

        public void SetResponseMessages(List<Message> messages)
        {
            ResponseMessages = messages;
            Update();
        }

        public void Update()
        {
            if (ResponseMessages.Count > 0)
            {
                if (ResponseMessages.Count == 1)
                {
                    ResponseFormatted = string.Join("\r\n\r\n", ResponseMessages.Select((m) => $"{m.Role}\r\n{m.Content}"));
                }
                else
                {
                    ResponseFormatted = string.Join("\r\n\r\n", ResponseMessages.Select((m, i) => $"----- Run:{i + 1} -----\r\n{m.Role}\r\n{m.Content}"));
                }
                StringBuilder sb = new StringBuilder(string.Join(", ", ResponseMessages));
                sb.Replace("\r\n", " ").Replace("\n", " ");
                Response = sb.ToString();
            }
            else
            {
                ResponseFormatted = "";
                Response = "";
            }
        }

        public void SetMarked(List<string> markOn)
        {
            if (markOn.Count == 0)
            {
                ClearMarked();
            }
            else
            {
                var matches = Regex.Matches(ResponseFormatted, string.Join("|", markOn.Select((m) => Regex.Escape(m))), RegexOptions.IgnoreCase, new TimeSpan(0,0,30));

                Marks = matches.Cast<Match>().Select((m) => m.Value).ToList();
                IsMarked = Marks.Count > 0;
            }
        }

        public void ClearMarked()
        {
            Marks = new List<string>();
            IsMarked = false;
        }

        public override string ToString()
        {
            return Name;
        }
    }
}
